package com.azr.jesus.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONUtil;
import com.azr.jesus.common.constants.Constants;
import com.azr.jesus.common.dto.UserDTO;
import com.azr.jesus.common.dto.UserPasswordDTO;
import com.azr.jesus.common.factory.AsyncFactory;
import com.azr.jesus.common.jwt.TokenUtils;
import com.azr.jesus.common.domain.HttpStatus;
import com.azr.jesus.common.manager.AsyncManager;
import com.azr.jesus.entity.SysMenu;
import com.azr.jesus.entity.User;
import com.azr.jesus.entity.UserRole;
import com.azr.jesus.exception.ServiceException;
import com.azr.jesus.mapper.RoleMenuMapper;
import com.azr.jesus.mapper.UserMapper;
import com.azr.jesus.mapper.UserRoleMapper;
import com.azr.jesus.service.ISysMenuService;
import com.azr.jesus.service.IUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import sun.misc.MessageUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 * @author:: Xiong
 * @date:: 2022/10/30 20:10
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private ISysMenuService menuService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    public static final String USER_INFO = "USER_INFO";

    @Override
    public UserDTO login(UserDTO userDTO) {
        // 用户密码 md5加密
        userDTO.setPassword(SecureUtil.md5(userDTO.getPassword()));
        User one = getUser(userDTO);
        if (one != null) {
            BeanUtil.copyProperties(one, userDTO, true);
            // 设置token
            String token = TokenUtils.getToken(one.getUserId().toString(), one.getPassword());
            userDTO.setToken(token);
            // 设置菜单
            userDTO.setMenus(getRoleMenus(one));
            // 将用户信息存到redis
            stringRedisTemplate.opsForValue().set(USER_INFO, JSONUtil.toJsonStr(userDTO));
            AsyncManager.me().execute(AsyncFactory.recordLoginInfo(one.getUserName(), Constants.LOGIN_SUCCESS, "登录成功！"));
            return userDTO;
        } else {
            throw new ServiceException(HttpStatus.NO_CONTENT, "用户名或密码不正确");
        }
    }

    @Override
    public User register(UserDTO userDTO) {
        // 用户密码 md5加密
        userDTO.setPassword(SecureUtil.md5(userDTO.getPassword()));
        User one = getUser(userDTO);
        if (one == null) {
            one = new User();
            BeanUtil.copyProperties(userDTO, one, true);
            save(one);
            return one;
        } else {
            throw new ServiceException(HttpStatus.ERROR, "用户已存在");
        }
    }

    @Override
    public List<Long> getRoleMenu(Long userId) {
        return userRoleMapper.selectByUserId(userId);
    }

    @Override
    public void setUserRole(Long userId, List<Long> roleIds) {
        // 先删除
        userRoleMapper.deleteByUserId(userId);
        // 再绑定
        for (Long roleId : roleIds) {
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(roleId);
            userRoleMapper.insert(userRole);
        }
    }

    @Override
    public int updatePassword(UserPasswordDTO userPasswordDTO) {
        int update = userMapper.updatePassword(userPasswordDTO);
        if (update < 1) {
            throw new ServiceException(HttpStatus.BUSINESS_ERROR, "密码错误");
        }
        return update;
    }

    /**
     * 获取用户信息
     *
     * @param userDto
     * @return
     */
    private User getUser(UserDTO userDto) {
        QueryWrapper<User> query = new QueryWrapper<>();
        query.eq("user_name", userDto.getUserName());
        query.eq("password", userDto.getPassword());
        User one;
        try {
            one = getOne(query);
        } catch (Exception e) {
            throw new ServiceException(HttpStatus.ERROR, "系统错误");
        }
        return one;
    }


    /**
     * 设置角色菜单
     *
     * @param one
     * @return
     */
    @NotNull
    private List<SysMenu> getRoleMenus(User one) {
        // 获取用户角色信息
        List<Long> roleIds = userRoleMapper.selectByUserId(one.getUserId());
        // 设置用户的菜单列表
        List<SysMenu> roleMenus = new ArrayList<>();
        // 查出系统所有的菜单(树形)
        List<SysMenu> menus = menuService.findMenus("");
        for (Long roleId : roleIds) {
            // 当前角色的所有菜单id集合
            List<Long> menuIds = roleMenuMapper.selectByRoleId(roleId);
            // 筛选当前用户角色的菜单
            for (SysMenu menu : menus) {
                if (menuIds.contains(menu.getMenuId())) {
                    roleMenus.add(menu);
                }
                List<SysMenu> children = menu.getChildren();
                // removeIf()  移除 children 里面不在 menuIds集合中的 元素
                children.removeIf(child -> !menuIds.contains(child.getMenuId()));
            }
        }

        return roleMenus.stream().distinct().collect(Collectors.toList());
    }
}
